//===--- FixedPoint.swift.gyb ---------------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

%{

from SwiftIntTypes import all_integer_types, int_max_bits, should_define_truncating_bit_pattern_init

#
# Utility code for later in this template
#
def hexify(n):
    """Return a legible hex representation of n, using '_' separators """
    z = '%X' % n
    l = len(z)
    r = []
    while z:
        r.insert(0, z[-4:])
        z = z[:-4]
    return '0x' + '_'.join(r)

# Number of bits in the Builtin.Word type
word_bits = int(CMAKE_SIZEOF_VOID_P) * 8

# Number of bits in integer literals.
builtinIntLiteralBits = 2048

def maskBits(n):
    """Return an n-bit mask in hex"""
    return hexify((1 << n) - 1)

IntMax = 'Int%s' % int_max_bits
UIntMax = 'UInt%s' % int_max_bits
}%

/// The largest native signed integer type.
public typealias IntMax = ${IntMax}
/// The largest native unsigned integer type.
public typealias UIntMax = ${UIntMax}

/// This protocol is an implementation detail of `Integer`; do
/// not use it directly.
@_show_in_interface
public protocol _Integer
  : _BuiltinIntegerLiteralConvertible,
    IntegerLiteralConvertible,
    CustomStringConvertible,
    Hashable,
    IntegerArithmetic,
    BitwiseOperations,
    _Incrementable
{
}

/// A set of common requirements for Swift's integer types.
public protocol Integer : _Integer, Strideable {}

/// This protocol is an implementation detail of `SignedInteger`;
/// do not use it directly.
@_show_in_interface
public protocol _SignedInteger : _Integer, SignedNumber {
  /// Represent this number using Swift's widest native signed integer
  /// type.
  func toIntMax() -> IntMax

  /// Convert from Swift's widest signed integer type, trapping on
  /// overflow.
  init(_: IntMax)
}

/// A set of common requirements for Swift's signed integer types.
public protocol SignedInteger : _SignedInteger, Integer {
  /// Represent this number using Swift's widest native signed integer
  /// type.
  func toIntMax() -> IntMax

  /// Convert from Swift's widest signed integer type, trapping on
  /// overflow.
  init(_: IntMax)
}

extension SignedInteger {
  // FIXME(ABI): using Int as the return value is wrong.
  @_transparent
  public func distance(to other: Self) -> Int {
    return numericCast((numericCast(other) as IntMax) - numericCast(self))
  }

  // FIXME(ABI): using Int as the return value is wrong.
  @_transparent
  public func advanced(by n: Int) -> Self {
    return numericCast((numericCast(self) as IntMax) + numericCast(n))
  }
}

/// This protocol is an implementation detail of `UnsignedInteger`;
/// do not use it directly.
@_show_in_interface
public protocol _DisallowMixedSignArithmetic : _Integer {
  // Used to create a deliberate ambiguity in cases like UInt(1) +
  // Int(1), which would otherwise compile due to the arithmetic
  // operators defined for Strideable types (unsigned types are
  // Strideable).
  associatedtype _DisallowMixedSignArithmetic : SignedInteger = Int
}

/// A set of common requirements for Swift's unsigned integer types.
public protocol UnsignedInteger : _DisallowMixedSignArithmetic, Integer {
  /// Represent this number using Swift's widest native unsigned
  /// integer type.
  func toUIntMax() -> UIntMax

  /// Convert from Swift's widest unsigned integer type, trapping on
  /// overflow.
  init(_: UIntMax)
}

extension UnsignedInteger {
  // FIXME(ABI): using Int as the return value is wrong.
  @_transparent
  public func distance(to other: Self) -> Int {
    return numericCast((numericCast(other) as IntMax) - numericCast(self))
  }

  // FIXME(ABI): using Int as the return value is wrong.
  @_transparent
  public func advanced(by n: Int) -> Self {
    return numericCast((numericCast(self) as IntMax) + numericCast(n))
  }
}

/// Convert `x` to type `U`, trapping on overflow in -Onone and -O
/// builds.
///
/// Typically used to do conversion to any contextually-deduced
/// integer type:
///
///     func f(_ x: Int32) {}
///     func g(_ x: Int64) { f(numericCast(x)) }
public func numericCast<
  T : _SignedInteger, U : _SignedInteger
>(_ x: T) -> U {
  return U(x.toIntMax())
}

/// Convert `x` to type `U`, trapping on overflow in -Onone and -O
/// builds.
///
/// Typically used to do conversion to any contextually-deduced
/// integer type:
///
///     func f(_ x: UInt32) {}
///     func g(_ x: UInt64) { f(numericCast(x)) }
public func numericCast<
  T : UnsignedInteger, U : UnsignedInteger
>(_ x: T) -> U {
  return U(x.toUIntMax())
}

/// Convert `x` to type `U`, trapping on overflow in -Onone and -O
/// builds.
///
/// Typically used to do conversion to any contextually-deduced
/// integer type:
///
///     func f(_ x: UInt32) {}
///     func g(_ x: Int64) { f(numericCast(x)) }
public func numericCast<
  T : _SignedInteger, U : UnsignedInteger
>(_ x: T) -> U {
  return U(UIntMax(x.toIntMax()))
}

/// Convert `x` to type `U`, trapping on overflow in -Onone and -O
/// builds.
///
/// Typically used to do conversion to any contextually-deduced
/// integer type:
///
///     func f(_ x: Int32) {}
///     func g(_ x: UInt64) { f(numericCast(x)) }
public func numericCast<
T : UnsignedInteger, U : _SignedInteger
>(_ x: T) -> U {
  return U(IntMax(x.toUIntMax()))
}

//===--- Loop over all integer types --------------------------------------===//
% for self_ty in all_integer_types(word_bits):
%   bits = self_ty.bits
%   signed = self_ty.is_signed
%   (sign, ext) = ('s', 'sext') if signed else ('u', 'zext')
%   Self = self_ty.stdlib_name
%   BuiltinName = self_ty.builtin_name
%   OtherSelf = self_ty.get_opposite_signedness().stdlib_name
%   Article = 'An' if bits == 8 else 'A'

% if self_ty.is_word:
/// ${'An un' if sign == 'u' else 'A '}signed integer value type.
///
/// On 32-bit platforms, `${Self}` is the same size as `${Self}32`, and
/// on 64-bit platforms, `${Self}` is the same size as `${Self}64`.
% else:
/// ${Article} ${bits}-bit ${'un' if sign == 'u' else ''}signed integer value
/// type.
% end
@_fixed_layout
public struct ${Self}
   : ${'SignedInteger' if sign == 's' else 'UnsignedInteger'},
     Comparable, Equatable {
  public // @testable
  var _value: Builtin.${BuiltinName}

  // FIXME: this declaration should be inferred.
  // <rdar://problem/18379938> Type checker refuses to use the default for
  // Int.Distance associated type

  /// Create an instance initialized to zero.
  @_transparent public
  init() {
    let maxWidthZero: IntMax = 0
    self._value = Builtin.truncOrBitCast_Int${int_max_bits}_${BuiltinName}(
       maxWidthZero._value)
  }

  @_transparent public
  init(_ _v: Builtin.${BuiltinName}) {
    self._value = _v
  }

  @_transparent public
  init(_bits: Builtin.${BuiltinName}) {
    self._value = _bits
  }

% if self_ty.is_word:
  @_transparent
  public // @testable
  init(_ _v: Builtin.Word) {
% if BuiltinName == 'Int32':
    self._value = Builtin.truncOrBitCast_Word_Int32(_v)
% elif BuiltinName == 'Int64':
    self._value = Builtin.zextOrBitCast_Word_Int64(_v)
% end
  }

  @_transparent
  public // @testable
  var _builtinWordValue: Builtin.Word {
% if BuiltinName == 'Int32':
    return Builtin.zextOrBitCast_Int32_Word(_value)
% elif BuiltinName == 'Int64':
    return Builtin.truncOrBitCast_Int64_Word(_value)
% end
  }
% end


%  if bits > 8:
  /// Creates an integer from its big-endian representation, changing the
  /// byte order if necessary.
  @_transparent public
  init(bigEndian value: ${Self}) {
#if _endian(big)
    self = value
#else
    self = ${Self}(Builtin.int_bswap_${BuiltinName}(value._value) )
#endif
  }

  /// Creates an integer from its little-endian representation, changing the
  /// byte order if necessary.
  @_transparent public
  init(littleEndian value: ${Self}) {
#if _endian(little)
    self = value
#else
    self = ${Self}(Builtin.int_bswap_${BuiltinName}(value._value) )
#endif
  }
%  end

  @_transparent public
  init(_builtinIntegerLiteral value: Builtin.Int${builtinIntLiteralBits}) {
    self = ${Self}(Builtin.s_to_${sign}_checked_trunc_Int${builtinIntLiteralBits}_${BuiltinName}(value).0)
  }

  /// Create an instance initialized to `value`.
  @_transparent public
  init(integerLiteral value: ${Self}) {
    self = value
  }

%  if bits > 8:
  /// Returns the big-endian representation of the integer, changing the
  /// byte order if necessary.
  public var bigEndian: ${Self} {
#if _endian(big)
    return self
#else
    return ${Self}(Builtin.int_bswap_${BuiltinName}(_value))
#endif
  }
  /// Returns the little-endian representation of the integer, changing the
  /// byte order if necessary.
  public var littleEndian: ${Self} {
#if _endian(little)
    return self
#else
    return ${Self}(Builtin.int_bswap_${BuiltinName}(_value))
#endif
  }
% end

%  if bits > 8:
  /// Returns the current integer with the byte order swapped.
  public var byteSwapped: ${Self} {
    return ${Self}(Builtin.int_bswap_${BuiltinName}(_value))
  }
% end

% max = maskBits((bits - 1) if signed else bits)
  @_transparent public
  static var max: ${Self} { return ${max} }
  @_transparent public
  static var min: ${Self} { return ${'-%s-1' % max if signed else '0'} }
  @_transparent
  public static var _sizeInBits: ${Self} { return ${bits} }
  public static var _sizeInBytes: ${Self} { return ${bits}/8 }
}

extension ${Self} : Hashable {
  /// The hash value.
  ///
  /// **Axiom:** `x == y` implies `x.hashValue == y.hashValue`.
  ///
  /// - Note: The hash value is not guaranteed to be stable across
  ///   different invocations of the same program.  Do not persist the
  ///   hash value across program runs.
  public var hashValue: Int {
    @inline(__always)
    get {
% if bits <= word_bits and signed:
      // Sign extend the value.
      return Int(self)
% elif bits <= word_bits and not signed:
      // Sign extend the value.
      return Int(${OtherSelf}(bitPattern: self))
% elif bits == word_bits * 2:
      // We have twice as many bits as we need to return.
      return
        Int(truncatingBitPattern: self) ^
        Int(truncatingBitPattern: self >> 32)
% else:
      _Unimplemented()
% end
    }
  }
}

extension ${Self} : CustomStringConvertible {
  /// A textual representation of `self`.
  public var description: String {
% if signed:
    return _int64ToString(self.toIntMax())
% else:
    return _uint64ToString(self.toUIntMax())
% end
  }
}

// Operations that return an overflow bit in addition to a partial result,
// helpful for checking for overflow when you want to handle it.
extension ${Self} {
% for Method, op in [('add', 'add'), ('subtract', 'sub'), ('multiply', 'mul')]:
  /// ${Method.capitalize()} `lhs` and `rhs`, returning a result and a
  /// `Bool` that is `true` iff the operation caused an arithmetic
  /// overflow.
  @_transparent public
  static func ${Method}WithOverflow(_ lhs: ${Self}, _ rhs: ${Self}) -> (${Self}, overflow: Bool) {
    let tmp = Builtin.${sign}${op}_with_overflow_${BuiltinName}(lhs._value, rhs._value, false._value)
    return (${Self}(tmp.0), Bool(tmp.1))
  }
% end

% for Method, op in [('divide', 'div'), ('remainder', 'rem')]:
  /// Divide `lhs` and `rhs`, returning
  /// ${'a result' if op == 'div' else 'the remainder'} and a `Bool`
  /// that is `true` iff the operation caused an arithmetic overflow.
  @_transparent public
  static func ${Method}WithOverflow(_ lhs: ${Self}, _ rhs: ${Self}) -> (${Self}, overflow: Bool) {
    if rhs == 0 {
      return (0, true)
    }
% if signed:
    if lhs == ${Self}.min && rhs == -1 {
      return (0, true)
    }
% end
    // FIXME: currently doesn't detect overflow -- blocked by:
    // <rdar://15735295> Need [su]{div,rem}_with_overflow IR
    let tmp = Builtin.${sign}${op}_${BuiltinName}(lhs._value, rhs._value)
    return (${Self}(tmp), false)
  }
%end

% (U, un) = ('','') if signed else ('U','un')
  /// Represent this number using Swift's widest native ${un}signed
  /// integer type.
  @_transparent public
  func to${U}IntMax() -> ${U}IntMax {
    return ${'self' if Self == U+'Int%s'%int_max_bits else U+'IntMax(self)'}
  }
% if not signed:
  /// Explicitly convert to `IntMax`${', trapping on overflow (except in -Ounchecked builds)' if bits == int_max_bits else ''}.
  @_transparent public
  func toIntMax() -> IntMax {
    return IntMax(toUIntMax())
  }
% end
}

% if signed:
@_transparent
extension ${Self} : SignedNumber {}
% end


%{
import gyb

fixed_fixed_conversion_function = gyb.parse_template("fixed_fixed_conversion_function",
"""
%
  let src = value._value
  let result: (value: Builtin.${BuiltinName}, error: Builtin.Int1)
%
%       if srcBits == bits and srcSign == sign: # Exact same size/signedness.
  result = (src, false._value)
%
%       elif srcBits == bits:  # Same size, switching signs.
  result = Builtin.${srcSign}_to_${sign}_checked_conversion_Int${srcBits}(src)
%
%       elif srcBits > bits:  # Larger input, check for truncation.
  result = Builtin.${srcSign}_to_${sign}_checked_trunc_Int${srcBits}_Int${bits}(src)
%
%       elif srcSigned and not signed: # Smaller size input, signed going to unsigned.
  let (tmp, signError) = Builtin.s_to_u_checked_conversion_Int${srcBits}(src)
  result = (Builtin.${srcExt}_Int${srcBits}_Int${bits}(tmp), signError)
%
%       else: # Smaller size input, unsigned to signed or unsigned to unsigned.
  result = (Builtin.${srcExt}_Int${srcBits}_Int${bits}(src), false._value)
%       end
% 
% if not safelyConvertible:
  ${error_check}
% end
  self._value = result.value
""")
}%

% for src_ty in all_integer_types(word_bits):
%    srcBits = src_ty.bits
%    srcSigned = src_ty.is_signed
%    Src = src_ty.stdlib_name
%    (srcSign, srcExt) = ('s', 'sext') if srcSigned else ('u', 'zext')
%    safelyConvertible = (srcBits < bits and (srcSign == sign or signed)) or (srcBits == bits and srcSign == sign)

@_transparent
extension ${Self} {

  @_transparent
  public init(_ value: ${Src}) {
    ${gyb.execute_template(
        fixed_fixed_conversion_function,
        error_check="Builtin.condfail(result.error)",
        **locals()
        )
    }
  }
    
% if safelyConvertible:
  @available(*, message: "Converting ${Src} to ${Self} will always succeed.")
% end
  @_transparent 
  public init?(exactly value: ${Src}) {
    ${gyb.execute_template(
        fixed_fixed_conversion_function,
        error_check="if Bool(result.error) == true { return nil }",
        **locals()
        )
    }
  }

%    if should_define_truncating_bit_pattern_init(src_ty=src_ty, dst_ty=self_ty):
  /// Construct a `${Self}` having the same bitwise representation as
  /// the least significant bits of the provided bit pattern.
  ///
  /// No range or overflow checking occurs.
  @_transparent
  public init(truncatingBitPattern: ${Src}) {
%
    let src = truncatingBitPattern._value
%
%       if self_ty.bits == src_ty.bits:
    let dstNotWord = src
%       else:
    let dstNotWord = Builtin.trunc_Int${srcBits}_Int${bits}(src)
%       end
%
    self._value = dstNotWord
  }

%    end
}
% end

extension ${Self} {
  /// Construct a `${Self}` having the same memory representation as
  /// the `${OtherSelf}` `bitPattern`.  No range or overflow checking
  /// occurs, and the resulting `${Self}` may not have the same numeric
  /// value as `bitPattern`--it is only guaranteed to use the same
  /// pattern of bits.
  @_transparent
  public init(bitPattern: ${OtherSelf}) {
    self._value = bitPattern._value
  }
}

// Operations with potentially-static overflow checking
//
// FIXME: must use condfail in these operators, rather than
// overflowChecked, pending <rdar://problem/16271923> so that we don't
// foil static checking for numeric overflows.
% for op, method in ('+','add'), ('*','mul'), ('-','sub'):
@_transparent
public func ${op} (lhs: ${Self}, rhs: ${Self}) -> ${Self} {
  let (result, error) = Builtin.${sign}${method}_with_overflow_${BuiltinName}(
    lhs._value, rhs._value, true._value)
  // return overflowChecked((${Self}(result), Bool(error)))
  Builtin.condfail(error)
  return ${Self}(result)
}
% end

% for op, inst in [('/', 'div'), ('%', 'rem')]:
@_transparent
public func ${op}(lhs: ${Self}, rhs: ${Self}) -> ${Self} {
  Builtin.condfail((rhs == 0)._value)
% if signed:
  Builtin.condfail(((lhs == ${Self}.min) && (rhs == -1))._value)
% end
  // FIXME: currently doesn't detect overflow -- blocked by:
  // <rdar://15735295> Need [su]{div,rem}_with_overflow IR
  let tmp = Builtin.${sign}${inst}_${BuiltinName}(lhs._value, rhs._value)
  return ${Self}(tmp)
}
%end

// Bitwise negate
/// Returns the inverse of the bits set in the argument.
///
/// - SeeAlso: `BitwiseOperations`
@_transparent
public prefix func ~(rhs: ${Self}) -> ${Self} {
  let mask = ${Self}.subtractWithOverflow(0, 1).0
  return ${Self}(Builtin.xor_${BuiltinName}(rhs._value, mask._value))
}

% for op, name, comment in (
%   ('==', 'eq', 'the two arguments have equal values'),
%   ('!=', 'ne', 'the two arguments have unequal values'),
%   ('<', sign + 'lt', 'the first argument is less than the second argument'),
%   ('<=', sign + 'le', 'the first argument is less than or equal to the second argument'),
%   ('>', sign + 'gt', 'the first argument is greater than the second argument'),
%   ('>=', sign + 'ge', 'the first argument is greater than or equal to the second argument'),
% ):
/// Returns a Boolean value that indicates whether
/// ${comment}.
///
/// - SeeAlso: `Equatable`, `Comparable`
@_transparent
public func ${op} (lhs: ${Self}, rhs: ${Self}) -> Bool {
  return Bool(Builtin.cmp_${name}_${BuiltinName}(lhs._value, rhs._value))
}
% end

% for op, name in (('<<','shl'), ('>>','ashr' if signed else 'lshr')):
@_transparent
public func ${op} (lhs: ${Self}, rhs: ${Self}) -> ${Self} {
% if signed:
  _precondition(U${Self}(rhs) < U${Self}._sizeInBits,
      "shift amount is larger than type size in bits")
% else:
  _precondition(rhs < ${Self}._sizeInBits,
      "shift amount is larger than type size in bits")
% end
  return ${Self}(Builtin.${name}_${BuiltinName}(lhs._value, rhs._value))
}
% end

% for op, name, comment in (
%   ('&', 'and', 'intersection of bits set in'),
%   ('^', 'xor', 'bits that are set in exactly one of'),
%   ('|', 'or', 'union of bits set in'),
% ):
/// Returns the ${comment} the two arguments.
///
/// - SeeAlso: `BitwiseOperations`
@_transparent
public func ${op} (lhs: ${Self}, rhs: ${Self}) -> ${Self} {
  return ${Self}(Builtin.${name}_${BuiltinName}(lhs._value, rhs._value))
}

/// Calculates the ${comment} the two arguments
/// and stores the result in the first argument.
///
/// - SeeAlso: `BitwiseOperations`
@_transparent
public func ${op}=(lhs: inout ${Self}, rhs: ${Self}) {
  lhs = lhs ${op} rhs
}
% end

// Bitwise operations
@_transparent
extension ${Self} : BitwiseOperations {
  /// The empty bitset of type `${Self}`.
  public static var allZeros: ${Self} { return 0 }
}

// Compound assignments
% for op in '+', '-', '*', '<<', '>>':
@_transparent
public func ${op}=(lhs: inout ${Self}, rhs: ${Self}) {
  lhs = lhs ${op} rhs
}
% end

// Create an ambiguity when indexing or slicing
// Range[OfStrideable]<${Self}> outside a generic context.  See
// Range.swift for details.
extension ${Self} {
  public typealias _DisabledRangeIndex = ${Self}
}

// Prefix and postfix increment and decrement.

@_transparent
@available(*, unavailable, message: "it has been removed in Swift 3")
@discardableResult
public prefix func ++ (x: inout ${Self}) -> ${Self} {
  x = x + 1
  return x
}

@_transparent
@available(*, unavailable, message: "it has been removed in Swift 3")
@discardableResult
public postfix func ++ (x: inout ${Self}) -> ${Self} {
  let ret = x
  x = x + 1
  return ret
}

@_transparent
@available(*, unavailable, message: "it has been removed in Swift 3")
@discardableResult
public prefix func -- (x: inout ${Self}) -> ${Self} {
  x = x - 1
  return x
}

@_transparent
@available(*, unavailable, message: "it has been removed in Swift 3")
@discardableResult
public postfix func -- (x: inout ${Self}) -> ${Self} {
  let ret = x
  x = x - 1
  return ret
}

% if signed:
// TODO: Consider removing the underscore.
/// Returns the argument and specifies that the value is not negative.
/// It has only an effect if the argument is a load or call.
@_transparent
public func _assumeNonNegative(_ x: ${Self}) -> ${Self} {
  _sanityCheck(x >= 0)
  return ${Self}(Builtin.assumeNonNegative_${BuiltinName}(x._value))
}
% end

% end

% fixedBitWidths = [2**x for x in range(3, 8) if 2**x <= 2 * word_bits]
% for bits in fixedBitWidths:
@_transparent
public func _leadingZeros(_ x: Builtin.Int${bits}) -> Builtin.Int${bits} {
  return Builtin.int_ctlz_Int${bits}(x, true._value)
}
% end

//===--- End loop over all integer types ----------------------------------===//

internal func _unsafePlus(_ lhs: Int, _ rhs: Int) -> Int {
#if INTERNAL_CHECKS_ENABLED
  return lhs + rhs
#else
  return lhs &+ rhs
#endif
}

internal func _unsafeMinus(_ lhs: Int, _ rhs: Int) -> Int {
#if INTERNAL_CHECKS_ENABLED
  return lhs - rhs
#else
  return lhs &- rhs
#endif
}

internal func _unsafeMultiply(_ lhs: Int, _ rhs: Int) -> Int {
#if INTERNAL_CHECKS_ENABLED
  return lhs * rhs
#else
  return lhs &* rhs
#endif
}

@available(*, unavailable, renamed: "Integer")
public typealias IntegerType = Integer

@available(*, unavailable, renamed: "SignedInteger")
public typealias SignedIntegerType = SignedInteger

@available(*, unavailable, renamed: "UnsignedInteger")
public typealias UnsignedIntegerType = UnsignedInteger

// ${'Local Variables'}:
// eval: (read-only-mode 1)
// End:
